package com.jhy.core.helper;

import cn.dev33.satoken.SaManager;
import cn.dev33.satoken.session.SaSession;
import cn.dev33.satoken.stp.SaLoginModel;
import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.util.ObjectUtil;

import com.jhy.core.domain.LoginUser;
import com.jhy.core.enums.DeviceType;
import com.jhy.core.enums.UserType;
import com.jhy.core.utils.Check;
import com.jhy.core.utils.ServletUtils;
import com.jhy.exception.BaseException;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;
import org.springframework.util.StringUtils;

import javax.servlet.http.HttpServletRequest;
import java.util.List;
import java.util.Set;
import java.util.concurrent.TimeoutException;
import java.util.stream.Collectors;

/**
 * 登录鉴权助手
 *
 * user_type 为 用户类型 同一个用户表 可以有多种用户类型 例如 pc,app
 * deivce 为 设备类型 同一个用户类型 可以有 多种设备类型 例如 web,ios
 * 可以组成 用户类型与设备类型多对多的 权限灵活控制
 *
 * 多用户体系 针对 多种用户类型 但权限控制不一致
 * 可以组成 多用户类型表与多设备类型 分别控制权限
 *
 * @author Lion Li
 */
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public class LoginHelper {

    public static final String JOIN_CODE = ":";
    public static final String LOGIN_USER_KEY = "loginUser";

    private static final ThreadLocal<LoginUser> LOGIN_CACHE = new ThreadLocal<>();

    /**
     * 登录系统
     *
     * @param loginUser 登录用户信息
     */
    public static void login(LoginUser loginUser) {
        LOGIN_CACHE.set(loginUser);
        StpUtil.login(loginUser.getLoginId());
        setLoginUser(loginUser);
    }

    /**
     * 登录系统 基于 设备类型
     * 针对相同用户体系不同设备
     *
     * @param loginUser 登录用户信息
     */
    public static void loginByDevice(LoginUser loginUser, DeviceType deviceType) {
        LOGIN_CACHE.set(loginUser);
        StpUtil.login(loginUser.getLoginId());
        setLoginUser(loginUser);
    }

    private static void concurrentLogin(LoginUser loginUser, DeviceType deviceType) {
        SaLoginModel loginModel = new SaLoginModel().setDevice(deviceType.getDevice());
        loginModel.build(SaManager.getConfig());
        String tokenValue = StpUtil.stpLogic.createTokenValue(loginUser.getLoginId(), loginModel.getDeviceOrDefault(), loginModel.getTimeout(), loginModel.getExtraData());
        SaSession session = StpUtil.stpLogic.getSessionByLoginId(loginUser.getLoginId(), true);
        session.updateMinTimeout(loginModel.getTimeout());
        session.addTokenSign(tokenValue, loginModel.getDeviceOrDefault());
        StpUtil.stpLogic.saveTokenToIdMapping(tokenValue, loginUser.getLoginId(), loginModel.getTimeout());
        StpUtil.stpLogic.getSaTokenDao().set(StpUtil.stpLogic.splicingKeyLastActivityTime(tokenValue), String.valueOf(System.currentTimeMillis()), SaManager.getConfig().getTimeout());
        SaManager.getSaTokenListener().doLogin("login", loginUser.getLoginId(), loginModel);
        StpUtil.stpLogic.setTokenValue(tokenValue, loginModel.getCookieTimeout());
    }

    /**
     * 设置用户数据(多级缓存)
     */
    public static void setLoginUser(LoginUser loginUser) {
        StpUtil.getTokenSession().set(LOGIN_USER_KEY, loginUser);
    }

    /**
     * 获取用户(多级缓存)
     */
    public static LoginUser getLoginUser() {
        LoginUser loginUser = LOGIN_CACHE.get();
        if (loginUser != null) {
            return loginUser;
        }
        return (LoginUser) StpUtil.getTokenSession().get(LOGIN_USER_KEY);
    }

    /**
     * 清除一级缓存 防止内存问题
     */
    public static void clearCache() {
        LOGIN_CACHE.remove();
    }

    /**
     * 获取用户id
     */
    public static Long getUserId() {
        LoginUser loginUser = getLoginUser();
        if (ObjectUtil.isNull(loginUser)) {
            String loginId = StpUtil.getLoginIdAsString();
            String userId = null;
            for (UserType value : UserType.values()) {
                if (loginId.contains(value.getUserType())) {
                    String[] strs = StringUtils.split(loginId, JOIN_CODE);
                    // 用户id在总是在最后
                    userId = strs[strs.length - 1];
                }
            }
            if (io.micrometer.core.instrument.util.StringUtils.isBlank(userId)) {
                throw new BaseException("登录用户: LoginId异常 => " + loginId);
            }
            return Long.parseLong(userId);
        }
        return loginUser.getUserId();
    }

    /**
     * 获取部门ID
     */
    public static Long getDeptId() {
        return getLoginUser().getDeptId();
    }

    /**
     * 获取用户账户
     */
    public static String getUsername() {
        return getLoginUser().getUsername();
    }

    /**
     * 获取用户昵称
     */
    public static String getNickName() {
        return getLoginUser().getNickName();
    }

    /**
     * 获取用户类型
     */
    public static UserType getUserType() {
        String loginId = StpUtil.getLoginIdAsString();
        return UserType.getUserType(loginId);
    }

//    /**
//     * 是否为管理员
//     *
//     * @param userId 用户ID
//     * @return 结果
//     */
//    public static boolean isAdmin(Long userId) {
//        return UserConstants.ADMIN_ID.equals(userId);
//    }
//
//    public static boolean isAdmin() {
//        return isAdmin(getUserId());
//    }
//
//    public static boolean checkRole(Boolean filterAdmin,String... roleName) {
//        List<RoleDTO> roles = LoginHelper.getLoginUser().getRoles();
//        if (!filterAdmin && LoginHelper.isAdmin()) {
//            // admin 直接返回
//            return true;
//        }
//        if (Check.isNoEmpty(roleName) && Check.isNoEmpty(roles)) {
//            Set<String> roleKeys = roles.stream().map(RoleDTO::getRoleKey).collect(Collectors.toSet());
//            for (String name : roleName) {
//                if (roleKeys.contains(name)) {
//                    return true;
//                }
//            }
//        }
//        return false;
//    }

    public static Boolean checkIsPc() {
        HttpServletRequest request = ServletUtils.getRequest();
        String header = request.getHeader("os-type");
        if (Check.isEmpty(header) || (Check.isNoEmpty(header) && !"pc".equals(header))) {
            return false;
        }
        return true;
    }
}
